﻿using iTool.Cloud.Center.Model;
using iTool.ClusterComponent;
using iTool.Common.Options;
using iToolService.Interfaces;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Threading.Tasks;

namespace Client.ConsoleApp
{
    class Program
    {
        /**
         1. StorageProvider  有状态
         2. ClusteringProvider  集群
         3. ReminderProvider   计划任务
         4. 提供 Sqllite Grain
         5. 提供 ClusterGrain 给每个集群
         */


        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            Task.WaitAll(RunMainAsync());

            Console.ReadKey();
        }

        private static async Task RunMainAsync()
        {
            var builder = new iToolClientBuilder();

            builder.UseAdoNetClustering(new AdoNetClusterOptions
            {
                AdoNetOptions = new AdoNetOptions
                {
                    DataSource = "127.0.0.1,2433",
                    UID = "sa",
                    PWD = "zhuJIAN320"
                },
                ClusterOptions = new ClusterIdentificationOptions(),
                ResponseTimeout = TimeSpan.FromSeconds(15)
            });

            var clusterHostClient = await builder.BuildAndConnectAsync();

            var storageService = clusterHostClient.GetService<IStorageService>("testSorage");
            string statevalue = await storageService.GetState();
            await storageService.Modify("akjsdhkasdhkjasdhkajsdhk");
            statevalue = await storageService.GetState();
            await storageService.Modify("568765lapsdkl;");
            statevalue = await storageService.GetState();
            await storageService.Remove();
            statevalue = await storageService.GetState();



            Console.WriteLine("Build And Connected!");

            while (true)
            {
                var input = Console.ReadLine();

                await ExcuterReaderAsync(clusterHostClient, input);


                var reader = clusterHostClient.GetService<IKeyValueReader>("keyvalue");

                Stopwatch sw = new Stopwatch();
                sw.Start();

                List<Task<string>> tasks = new List<Task<string>>(100010);
                Parallel.For(0, 20_000, index =>
                {
                    var task = reader.GetAsync();
                    tasks.Add(task);
                });

                await Task.WhenAll(tasks);

                await reader.SetAsync(input);

                Console.WriteLine("GetAsync:" + await reader.GetAsync());

                sw.Stop();
                Console.WriteLine($"timer:{sw.Elapsed.TotalMilliseconds}ms");
            }
        }


        /**
        1. 缓存分为 Reader 和 Storage 两种模式
        2. 直观上的区别 Reader 对比 Storage 有一下区别：
            - Reader 永远是异步的 || Storage反之。 Reader在服务器宕机断电等异常情况，可能会导致近期短时间内的写入/删除等操作失败
            - Reader 支持多线程并发读和写，所以性能更高。但是Reader的状态并非时时更新 || Storage 同redis 永远为单线程读写，对于单个Key的操作是原子性的
        3. 对于并发量，理论单个Key的并发量受到服务机器的内存操作及网络IO的最大限制。作者单机测试每秒在：10w QPS 耗时为 2.3s 成功率 100%。
        4. 由于原子性操作保证，从设计上尽可能避免单个Key内容过大。而导致的单热点性能瓶颈，测试应当对相关Key做适当拆分以达到目前吞吐量。
        5. 对于集群部署，单机宕机不会导致缓存服务不可能。会在短暂的延迟后恢复，这正常需要(1~3s)
        6. 单个Set集合不建议拥有巨大量级的内容，这将导致 [并集/交集..等] 吞吐量降低
        7. 框架对大批量Key支持友好，计算资源充足平稳的环境下。 无需担心Key的量级较大而导致的负面影响
         */


        private static async Task ExcuterReaderAsync(iToolClusterHostClient clusterHostClient, string input)
        {
            // key value
            {
                var service = clusterHostClient.GetService<IKeyValueReader>("keyvalue");
                // set
                await service.SetAsync(input);
                // get
                var task = await service.GetAsync();
                Console.WriteLine(task);
                // remove
                await service.RemoveAsync();

                // 并发测试
                // await TestCacheKeyValue(clusterHostClient,"keyvalue", input);
            }

            // hash
            {

                // set value
                var service = clusterHostClient.GetService<IHashReader>("hashTable");
                // set
                await service.SetAsync("fieldv", input);
                await service.SetAsync("fieldv1", input + "asjydajs");
                await service.SetAsync("fieldv1", input + "asjydajs");
                // get
                var fieldv = await service.GetAsync("fieldv");
                var fieldv1 = await service.GetAsync("fieldv1");
                // 不存在的key
                var fieldv2 = await service.GetAsync("fieldv1xxx");

                Console.WriteLine("fieldv:{0}", fieldv);
                Console.WriteLine("fieldv1:{0}", fieldv1);
                await service.RemoveAsync("fieldv");
                await service.RemoveAsync();

                // 并发测试
                // await TestCacheHash(clusterHostClient,"hashTable","fieldv", input);
            }

            // set
            {
                var service1 = clusterHostClient.GetService<ISetReader>("setList1");
                var service2 = clusterHostClient.GetService<ISetReader>("setList2");
                var service3 = clusterHostClient.GetService<ISetReader>("setList3");

                // 差集
                var list = await service3.GetDifferencesAsync(new string[] { "setList2" });
                // 交集
                list = await service3.GetIntersectAsync(new string[] { "setList2" });
                // 并集
                list = await service3.GetUnionAsync(new string[] { "setList1", "setList2" });
                await service2.RemoveAsync("4");
                list = await service2.GetAsync();


                //await service3.RemoveAsync();
                var xxasd = await service3.ExistsAsync("7");
                list = await service3.GetAsync();

                await service1.SetAsync("1");
                await service1.SetAsync("2");
                await service1.SetAsync("3");
                await service1.SetAsync("4");
                list = await service1.GetAsync();
                await service2.SetAsync("3");
                await service2.SetAsync("4");
                await service2.SetAsync("5");
                await service2.SetAsync("6");
                list = await service2.GetAsync();

                await service3.SetAsync("5");
                await service3.SetAsync("6");
                await service3.SetAsync("7");
                await service3.SetAsync("8");
                list = await service3.GetAsync();


                // 差集
                list = await service3.GetDifferencesAsync(new string[] { "setList2" });
                // 交集
                list = await service3.GetIntersectAsync(new string[] { "setList2" });
                // 并集
                list = await service3.GetUnionAsync(new string[] { "setList1", "setList2" });


                await service2.RemoveAsync("4");
                list = await service2.GetAsync();


                await service3.RemoveAsync();
                var xxas123d = await service3.ExistsAsync("7");
                list = await service3.GetAsync();
            }

            // zset
            {
                var service = clusterHostClient.GetService<IZSetReader>("zsetList");
                var slist = await service.GetAsync();
                var value = await service.GetByIndexAsync(10);
                value = await service.GetByScoreAsync(222);
                var list = await service.GetRangeAsync(10, 333);

                await service.SetAsync("asdfhagsd15", 15);
                await service.SetAsync("asdfhagsd16", 16);
                await service.SetAsync("asdfhagsd5", 5);
                await service.SetAsync("asdfhagsd4", 4);
                await service.SetAsync("asdfhagsd8", 8);
                await service.SetAsync("asdfhagsd17", 17);
                await service.SetAsync("asdfhagsd160", 160);
                await service.SetAsync("asdfhagsd222", 222);
                await service.SetAsync("asdfhagsd999", 999);


                slist = await service.GetAsync();
                value = await service.GetByIndexAsync(10);
                value = await service.GetByScoreAsync(222);
                list = await service.GetRangeAsync(10, 333);
            }
        }

        private static async Task ExcuterAsync(iToolClusterHostClient clusterHostClient, string input) 
        {
            // key value
            {
                var service = clusterHostClient.GetService<IKeyValueStorageService>("keyvalue");
                // set
                await service.SetAsync(input);
                // get
                var task = await service.GetAsync();
                Console.WriteLine(task);
                // remove
                await service.RemoveAsync();

                // 并发测试
                // await TestCacheKeyValue(clusterHostClient,"keyvalue", input);
            }

            // hash
            {

                // set value
                var service = clusterHostClient.GetService<IHashStorageService>("hashTable");
                // set
                await service.SetAsync("fieldv", input);
                await service.SetAsync("fieldv1", input + "asjydajs");
                await service.SetAsync("fieldv1", input + "asjydajs");
                // get
                var fieldv = await service.GetAsync("fieldv");
                var fieldv1 = await service.GetAsync("fieldv1");
                // 不存在的key
                var fieldv2 = await service.GetAsync("fieldv1xxx");

                Console.WriteLine("fieldv:{0}", fieldv);
                Console.WriteLine("fieldv1:{0}", fieldv1);
                await service.RemoveAsync("fieldv");
                await service.RemoveAsync();

                // 并发测试
                // await TestCacheHash(clusterHostClient,"hashTable","fieldv", input);
            }

            // set
            {
                var service1 = clusterHostClient.GetService<ISetStorageService>("setList1");
                var service2 = clusterHostClient.GetService<ISetStorageService>("setList2");
                var service3 = clusterHostClient.GetService<ISetStorageService>("setList3");

                // 差集
                var list = await service3.GetDifferencesAsync(new string[] { "setList2" });
                // 交集
                list = await service3.GetIntersectAsync(new string[] { "setList2" });
                // 并集
                list = await service3.GetUnionAsync(new string[] { "setList1", "setList2" });
                await service2.RemoveAsync("4");
                list = await service2.GetAsync();


                await service3.RemoveAsync();
                var xxasd = await service3.ExistsAsync("7");
                list = await service3.GetAsync();

                await service1.SetAsync("1");
                await service1.SetAsync("2");
                await service1.SetAsync("3");
                await service1.SetAsync("4");
                list = await service1.GetAsync();
                await service2.SetAsync("3");
                await service2.SetAsync("4");
                await service2.SetAsync("5");
                await service2.SetAsync("6");
                list = await service2.GetAsync();

                await service3.SetAsync("5");
                await service3.SetAsync("6");
                await service3.SetAsync("7");
                await service3.SetAsync("8");
                list = await service3.GetAsync();


                // 差集
                list = await service3.GetDifferencesAsync(new string[] { "setList2" });
                // 交集
                list = await service3.GetIntersectAsync(new string[] { "setList2" });
                // 并集
                list = await service3.GetUnionAsync(new string[] { "setList1", "setList2" });


                await service2.RemoveAsync("4");
                list = await service2.GetAsync();


                await service3.RemoveAsync();
                var xxas123d = await service3.ExistsAsync("7");
                list = await service3.GetAsync();
            }

            // zset
            {
                var service = clusterHostClient.GetService<IZSetStorageService>("zsetList");
                var slist = await service.GetAsync();
                var value = await service.GetByIndexAsync(10);
                value = await service.GetByScoreAsync(222);
                var list = await service.GetRangeAsync(10, 333);

                await service.SetAsync("asdfhagsd15", 15);
                await service.SetAsync("asdfhagsd16", 16);
                await service.SetAsync("asdfhagsd5", 5);
                await service.SetAsync("asdfhagsd4", 4);
                await service.SetAsync("asdfhagsd8", 8);
                await service.SetAsync("asdfhagsd17", 17);
                await service.SetAsync("asdfhagsd160", 160);
                await service.SetAsync("asdfhagsd222", 222);
                await service.SetAsync("asdfhagsd999", 999);


                slist = await service.GetAsync();
                value = await service.GetByIndexAsync(10);
                value = await service.GetByScoreAsync(222);
                list = await service.GetRangeAsync(10, 333);
            }
        }

        private static async Task TestCacheKeyValue(iToolClusterHostClient clusterHostClient, string key, string value)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            try
            {
                // set value
                var service = clusterHostClient.GetService<IKeyValueStorageService>(key);
                await service.SetAsync(value);

                List<Task<string>> tasks = new List<Task<string>>(100010);
                Parallel.For(0, 1_000, index =>
                {
                    // get value
                    var service = clusterHostClient.GetService<IKeyValueStorageService>(key);
                    var task = service.GetAsync();
                    tasks.Add(task);
                });
                await Task.WhenAll(tasks);

                await service.RemoveAsync();
            }
            catch (Exception ex)
            {
                Console.WriteLine("client:{0}", ex.Message);
            }
            sw.Stop();
            Console.WriteLine($"timer:{sw.Elapsed.TotalMilliseconds}ms");
        }

        private static async Task TestCacheHash(iToolClusterHostClient clusterHostClient, string table, string field,string value)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            try
            {
                // set value
                var service = clusterHostClient.GetService<IHashStorageService>(table);
                await service.SetAsync(field, value);

                List<Task<string>> tasks = new List<Task<string>>(100010);
                Parallel.For(0, 1_000, index =>
                {
                    // get value
                    var service = clusterHostClient.GetService<IHashStorageService>(table);
                    var task = service.GetAsync(field);
                    tasks.Add(task);
                });
                await Task.WhenAll(tasks);

                await service.RemoveAsync(field);

                await service.RemoveAsync();

                foreach (var item in tasks)
                {
                    Console.WriteLine("TestCacheHash field:{0}", item.Result);
                }

            }
            catch (Exception ex)
            {
                Console.WriteLine("client:{0}", ex.Message);
            }
            sw.Stop();
            Console.WriteLine($"timer:{sw.Elapsed.TotalMilliseconds}ms");
        }


    }
}
